# -*- coding: utf-8 -*-
"""
态势感知，记录更多的态势信息
"""
__authur__ = ' '

import json
import copy
import time

from .const import *
from copy import deepcopy
from ai.hexmap.handle_map import *
from .infer_paras import *


class Situation(object):
    """
    吴欣娟  2022/10/30
    设置situation类记录敌我双方态势信息
    """

    def __init__(self):
        self.id = []  # 我方id
        self.historical_positions = {}  # 我方历史位置； obj_id: last_point
        self.visual_field = {}  # 视野信息；pos: last_step  # pos: 格子编号；last_step: 最后在视野中的步数
        self.artillery_coverage = {}  # 炮火覆盖六角格
        """ (dict)
        pos: {
            "faction": 0 - 红 or 1 - 蓝,  # 炮火阵营
            "status": "当前状态 0-正在飞行 1-正在爆炸 2-无效",
            "step": int  # 当前状态更新的步数
        }
        """
        self.enemies = {}
        """(dict)
        obj_id:{'color': 0 - 红 or 1 - 蓝,  # 算子阵营
                'sub_type': int #算子类型
                'blood': int # 算子血量
                'historical_positions': [step, position] #；历史位置
                'workable_weapons': int # 可使用武器ID的列表
                'remain_bullet_nums':{} # 剩余弹药数量  与observation.operators[obj_id]["remain_bullet_nums"]的数据格式一致
                }
        """
        self.main_battlefield = set()  # 主要战场区域 [pos, pos, pos]
        self.main_battlefield_refer_work_center = []  # 将主战场区域选出三个中心点，将区域划分成三块
        self.main_battlefield_refer_work_center_standby = []
        self.patrol_standby = []  # 没有消失敌人的时候机动目标
        self.enemy_operators = None
        self.enemy_id = None  # 我方知道的敌方在场的算子id
        self.enemy_coord = None  # 确定的敌方算子最后一个坐标
        self.ufv_of_ifv = {}  # 敌方无人战车与所属重型战车的关系，当所属重型战车被消灭的时候清空所属无人战车的消息
        self.enemy = {}
        self.refer_city_changes = []  # 根据敌方修正夺控点的位置
        self.refer_city_changes_center = None  # 主战场区域的中心
        self.enemy_all_info = {}  # 按照时间顺序记录敌方所有算子的历史全部位置信息
        self.disappeared_enemy_diffusion = {}  # 消失的敌方算子可能在的区域
        self.disappeared_enemy_diffusion_distortion = []  # 扩散模型失真的实时敌人id列表（在看到的时候清空）
        self.coord_flag = False  # 我方算子是否有移动的标志位，有移动时是True
        self.my_see_scope = {}  # 每一个算子的针对不同类型的视野范围
        self.my_see_scope_cover = {}  # 每一个算子的针对不同类型的视野范围（认为敌方是掩蔽状态）
        self.my_see_scope_all0 = {0: set(),
                                  2: set(),
                                  5: set(),
                                  6: set()
                                  }  # 我方视野的全部，不考虑敌方掩蔽
        self.my_see_scope_all1 = {0: set(),
                                  2: set(),
                                  # 5: set(),
                                  # 6: set()
                                  }  # 我方视野的全部，考虑敌方的掩蔽（敌方56时没有掩蔽地形和掩蔽状态，和all0属性一致）

        # self.setup()  #
        # self.update()  # 在agent类的setup中传入想定数据进行数据初始化

        self.step_time = 0  # Situation上次更新时的时长

    def setup(self, agent):  # 初始化函数
        """
        吴欣娟  2022/10/30
        初始化态势信息函数
        """
        scenario = agent.scenario['scenario_id']
        scenario_data = agent.scenario  # 传入想定文件
        operators = scenario_data["operators"]
        self.enemy_operators = [operator for operator in operators if operator["color"] != agent.color]
        for operator in self.enemy_operators:
            self.enemy_all_info[operator["obj_id"]] = {
                "sub_type": operator["sub_type"],
                "all_pos": [[0, operator["cur_hex"]]]
            }
            # 初始化无人战车与重型战车的从属关系(聚合解聚之后的没考虑)
            if operator["sub_type"] == 4:
                if operator["car"]:
                    self.ufv_of_ifv[operator["car"]] = operator["obj_id"]
                if operator["launcher"]:
                    self.ufv_of_ifv[operator["launcher"]] = operator["obj_id"]
        self.enemy_coord = [operator["cur_hex"] for operator in self.enemy_operators]
        self.enemy_id = [operator["obj_id"] for operator in self.enemy_operators]
        a = agent.city_coord
        b = self.enemy_coord
        refer_CruiseMissle_regions = set()
        for i in a:
            direction_list = self.direction_list1(i, b)
            for direction in direction_list:
                refer_city_change = get_hex_in_direction(i, direction, 3)
                if refer_city_change not in self.refer_city_changes:
                    self.refer_city_changes.append(refer_city_change)
        for j in self.refer_city_changes:
            refer_CruiseMissle_region = agent.map.get_grid_distance(j, 0, 7)
            refer_CruiseMissle_regions = refer_CruiseMissle_regions.union(refer_CruiseMissle_region)
        self.main_battlefield = refer_CruiseMissle_regions
        # 求出偏移夺控点的中心
        row_list = []
        col_list = []
        for i in self.refer_city_changes:
            row_city, col_city = divmod(i, 100)
            row_list.append(row_city)  # 行
            col_list.append(col_city)  # 列
        row_min = min(row_list)
        col_min = min(col_list)
        row_max = max(row_list)
        col_max = max(col_list)
        self.refer_city_changes_center = (row_min + int(0.5 * (row_max - row_min))) * 100 + \
                                         (col_min + int(0.5 * (col_max - col_min)))
        for operator in scenario_data['operators']:
            obj_id = operator['obj_id']
            if operator['color'] == agent.color:
                self.id.append(obj_id)  # 根据想定文件初始化我方算子id
                # self.historical_positions.update({obj_id: operator['cur_hex']})  # 根据想定文件初始化我方算子历史位置
                for pos in self.main_battlefield:
                    self.visual_field.update({pos: [0, 0]})  # 根据通视初始化我方视野信息
            else:
                self.enemies.update({operator['obj_id']: {  # 根据想定文件初始化敌方算子id
                    'color': operator['color'],  # 根据想定文件初始化敌方阵营
                    'sub_type': operator['sub_type'],  # 根据想定文件初始化敌方算子类型
                    'blood': operator['blood'],  # 根据想定文件初始化敌方算子血量信息
                    'historical_positions': {operator['cur_hex']: [0, 0]},  # 根据想定文件初始化敌方历史位置
                    'workable_weapons': operator["carry_weapon_ids"],  # 根据想定文件初始化敌方武器id
                    'remain_bullet_nums': operator["remain_bullet_nums"]  # 根据想定文件初始化剩余弹药数量
                }})

        for operator in self.enemy_operators:
            self.enemy[operator["obj_id"]] = {
                "obj_id": operator["obj_id"],
                "color": operator["color"],
                "sub_type": operator["sub_type"],
                "keep": operator["keep"],
                "last_step": 0,
                "coord": operator["cur_hex"],
                "cur_blood": operator["max_blood"],
            }

    def direction_list1(self, refer_hex, tar_list):
        direction_list = []
        for i in tar_list:
            direction = get_direction(refer_hex, i)
            if direction not in direction_list:
                direction_list.append(direction)
        return direction_list

    def update(self, agent):  # 更新态势函数
        """
        吴欣娟  2022/10/30
        更新态势函数
        """
        agent.run_flag = False  # 当前态势计算结束后没有新的态势到来，释放资源
        situ = None
        while True:
            # 通过agent中的输入序列，序列取出态势
            agent.input_queue_lock.acquire()
            if agent.input_queue.full():
                agent.run_flag = False
                situ = agent.input_queue.get()
                agent.observation = agent.input_queue.get()
                agent.input_queue_lock.release()
                # print(agent.observation['time']['cur_step'])
            else:
                agent.input_queue_lock.release()
                # if agent.observation['time']['cur_step'] >= 2870:
                #     break
            if agent.run_flag:
                time.sleep(0.02)
                continue
            if not situ:
                continue
            # 在异步更新前获取同步更新中的situation属性
            self.id = situ.id
            self.enemy_id = situ.enemy_id
            self.enemy_coord = situ.enemy_coord
            self.enemy = situ.enemy
            self.enemy_all_info = situ.enemy_all_info
            # print(agent.observation['time']['cur_step'])
            # if agent.color == 0 and agent.role == 0:
            #     print("situd agent:", id(agent.controllable_ops))
            #     time.sleep(0.01)
            delete_id = []
            pos = None
            if agent.observation['judge_info']:  # 确保有裁决信息
                for judge_message in agent.observation['judge_info']:  # 遍历裁决信息
                    if judge_message["target_color"] == agent.color:
                        continue
                    if 'wp_id' in judge_message.keys():  # 排除雷场射击类型
                        if judge_message['att_obj_id'] in self.enemies.keys():  # 确保攻击算子是敌方算子；更新敌方算子弹药类型
                            if judge_message['wp_id'] == 72 or judge_message['wp_id'] == 88 or judge_message[
                                'wp_id'] == 89:  # 炮兵武器无弹药类型
                                pass
                            elif judge_message['wp_id'] == 75 or judge_message['wp_id'] == 76:  # 敌方攻击武器的弹药类型为小型导弹
                                self.enemies[judge_message['att_obj_id']]['remain_bullet_nums']['102']['102'] -= 1
                            elif judge_message['wp_id'] == 74 or judge_message['wp_id'] == 83:  # 敌方攻击武器的弹药类型为中型导弹
                                self.enemies[judge_message['att_obj_id']]['remain_bullet_nums']['101'] -= 1
                            elif judge_message['wp_id'] == 5 or judge_message['wp_id'] == 69 or judge_message[
                                'wp_id'] == 71 or judge_message['wp_id'] == 73 or judge_message[
                                'wp_id'] == 84:  # 敌方攻击武器的弹药类型为小重型导弹
                                self.enemies[judge_message['att_obj_id']]['remain_bullet_nums']['100'] -= 1
                            else:  # 敌方攻击武器的弹药类型为非导弹
                                self.enemies[judge_message['att_obj_id']]['remain_bullet_nums']['0'] -= 1
                        if judge_message["target_obj_id"] in self.enemies.keys():  # 更新敌方算子血量
                            if judge_message['damage'] > 0:  # 确保战损值为正
                                self.enemies[judge_message["target_obj_id"]]['blood'] -= judge_message["damage"]
                        if judge_message["att_obj_id"] in self.enemies.keys():  # 如果攻击算子为敌方的巡飞弹则自动消失
                            if judge_message["attack_sub_type"] == BopSubType.Helicopter:
                                self.enemies[judge_message["att_obj_id"]]['blood'] = 0
                    else:  # 雷场射击类型
                        if judge_message["target_obj_id"] in self.enemies.keys():  # 更新敌方算子血量
                            if judge_message['final_damage'] > 0:
                                self.enemies[judge_message["target_obj_id"]]['blood'] -= judge_message["final_damage"]
            for enemy_id, operator in self.enemies.items():  # 根据敌方算子血量更新敌方算子id、血量、历史位置、剩余弹药数、可使用武器信息
                if operator['blood'] < 1:
                    delete_id.append(enemy_id)
            for i in delete_id:
                if i in self.enemies.keys():
                    self.enemies.pop(i)
            if agent.observation['jm_points']:  # 确保有间瞄点信息
                for jm_point in agent.observation['jm_points']:
                    self.artillery_coverage.update({  # 更新间瞄点信息
                        jm_point['pos']: {
                            'faction': jm_point['color'],
                            'status': jm_point['status'],
                            'step': agent.observation['time']['cur_step'],
                            'obj_id': jm_point['obj_id']
                        }
                    })

            operators = agent.observation['operators'] + agent.observation["passengers"]
            # for obj_id in list(self.historical_positions.keys()):  # 删除我方历史位置中被消灭的算子
            #     if obj_id not in self.id:
            #         self.historical_positions.pop(obj_id)
            for operator in operators:
                if operator['obj_id'] in self.enemies.keys():  # 确保算子id是敌方的；根据我方算子视野更新敌方历史位置
                    enemy_id = operator['obj_id']
                    if operator['cur_hex'] in self.enemies[enemy_id]['historical_positions'].keys():  # 位置变化，添加新的位置
                        self.enemies[enemy_id]['historical_positions'][operator['cur_hex']][1] = \
                        agent.observation['time']['cur_step']
                    else:
                        self.enemies[enemy_id]['historical_positions'].update({operator['cur_hex']:
                            [agent.observation['time']['cur_step'], agent.observation['time']['cur_step']]})
                    if len(self.enemies[enemy_id]['historical_positions']) > 10:  # 历史位置只保留10个
                        for i in self.enemies[enemy_id]['historical_positions'].keys():
                            pos = i
                            break
                        if pos:
                            self.enemies[enemy_id]['historical_positions'].pop(pos)
                # if operator['obj_id'] in self.historical_positions.keys():  # 更新我方历史位置和视野信息
                #     obj_id = operator['obj_id']
                #     if operator['cur_hex'] != self.historical_positions[obj_id]:  # 我方算子位置改变才更新视野
                #         self.historical_positions[obj_id] = operator['cur_hex']
                #         for pos in self.main_battlefield:  # 需要修改，没有保证算子的可视范围，即默认无穷大
                #             if operator['type'] == 3: # 算子为飞机类型时视野计算与地面算子不同
                #                 if agent.map.can_see(operator['cur_hex'], pos, 2):
                #                     if agent.map.get_distance(operator['cur_hex'], pos) > 2:
                #                         continue  # 无人机和巡飞弹的观察距离是2，写直升机的时候需要更改
                #                     if pos in self.visual_field.keys():
                #                         self.visual_field[pos][0] = agent.observation['time']['cur_step']
                #             else:
                #                 if agent.map.can_see(operator['cur_hex'], pos, 0):
                #                     if pos in self.visual_field.keys():
                #                         self.visual_field[pos][0] = agent.observation['time']['cur_step']
            for operator in agent.observation["operators"]:
                obj_id = operator['obj_id']
                if operator['color'] == agent.color:
                    # 在这里初始化我方每个算子的视野信息
                    # 下标0表示车辆 2 表示人员 5表示无人机 6表示直升机 工事不会移动不考虑，巡飞弹没影响不考虑
                    if self.my_see_scope.get(obj_id) is None or operator["cur_hex"] != self.my_see_scope[obj_id]['cur_hex']:
                        # 属性没有对应的id和坐标发生变化的时候更新视野范围
                        self.coord_flag = True
                        self.my_see_scope[obj_id] = {
                            'cur_hex': operator["cur_hex"],
                            "sub_type": operator["sub_type"],
                            "scope": {0: agent.get_see_scope(operator, 0),
                                      2: agent.get_see_scope(operator, 2),
                                      5: agent.get_see_scope(operator, 5),
                                      6: agent.get_see_scope(operator, 6)
                                      }
                        }
                        self.my_see_scope_cover[obj_id] = {
                            'cur_hex': operator["cur_hex"],
                            "sub_type": operator["sub_type"],
                            "scope": {0: agent.get_see_scope1(operator, 0),
                                      2: agent.get_see_scope1(operator, 2),
                                      # 5: agent.get_see_scope1(operator, 5),
                                      # 6: agent.get_see_scope1(operator, 6)
                                      }
                        }
            history_id = list(self.my_see_scope.keys())
            presentable_id = [operator["obj_id"] for operator in agent.observation["operators"]
                              if operator["color"] == agent.color]  # 在场的我方算子id
            # 删除我方离开的算子的视野信息
            for i in history_id:
                # if i not in self.id:  # self.id是所有的，包括车上的，应该用在场的算子去掉乘客的
                if i not in presentable_id:
                    del self.my_see_scope[i]
                    del self.my_see_scope_cover[i]
            # 求出当前时刻的我方视野
            if self.coord_flag:
                self.my_see_scope_all0 = {0: set(),
                                          2: set(),
                                          5: set(),
                                          6: set()
                                          }  # 我方视野的全部，不考虑敌方掩蔽
                self.my_see_scope_all1 = {0: set(),
                                          2: set(),
                                          # 5: set(),
                                          # 6: set()
                                          }  # 我方视野的全部，考虑敌方掩蔽
                for j in self.my_see_scope:  # 遍历每一个算子视野，并上总体的
                    self.my_see_scope_all0 = {0: self.my_see_scope[j]["scope"][0].union(self.my_see_scope_all0[0]),
                                              2: self.my_see_scope[j]["scope"][2].union(self.my_see_scope_all0[2]),
                                              5: self.my_see_scope[j]["scope"][5].union(self.my_see_scope_all0[5]),
                                              6: self.my_see_scope[j]["scope"][6].union(self.my_see_scope_all0[6])
                                              }
                    self.my_see_scope_all1 = {0: self.my_see_scope_cover[j]["scope"][0].union(self.my_see_scope_all1[0]),
                                              2: self.my_see_scope_cover[j]["scope"][2].union(self.my_see_scope_all1[2]),
                                              # 5: self.my_see_scope_cover[j]["scope"][5].union(self.my_see_scope_all1[5]),
                                              # 6: self.my_see_scope_cover[j]["scope"][6].union(self.my_see_scope_all1[6])
                                              }
                # print(self.my_see_scope)
                # print("hah")
                # 在这里更新主战场区域视野信息
                update_poss = self.my_see_scope_all0[0].intersection(self.main_battlefield)
                for i in update_poss:
                    self.visual_field[i][0] = agent.observation['time']['cur_step']

                # 在这里进行扩散模型修正，并将标志位置位False
                not_type = [3, 7, 11, 12]
                vehicle = [0, 1, 4, 9, 10, 13, 14, 15, 17, 18]
                infantry = [2, 16]
                aircraft0 = [6, 8]
                aircraft1 = [5]
                my_see_scope = set()
                for i in self.disappeared_enemy_diffusion:
                    if self.disappeared_enemy_diffusion[i]['sub_type'] in not_type:
                        continue
                    elif self.disappeared_enemy_diffusion[i]['sub_type'] in aircraft0:
                        my_see_scope = self.my_see_scope_all0[6]
                    elif self.disappeared_enemy_diffusion[i]['sub_type'] in aircraft1:
                        my_see_scope = self.my_see_scope_all0[5]
                    elif self.disappeared_enemy_diffusion[i]['sub_type'] in infantry:
                        my_see_scope = self.my_see_scope_all1[2]  # 认为敌方人员和车辆是掩蔽状态进行修正
                    else:
                        my_see_scope = self.my_see_scope_all1[0]
                    diffusion_poss = set([pos for pos in
                                          self.disappeared_enemy_diffusion[i]["diffusion"]
                                          if self.disappeared_enemy_diffusion[i]["diffusion"][pos]
                                          > 0])  # 概率修正只有概率大于0的参与
                    pos_transfer = my_see_scope.intersection(diffusion_poss)
                    pos_receive = diffusion_poss - pos_transfer
                    # 依据掩蔽地形修正
                    if not pos_receive or i in self.disappeared_enemy_diffusion_distortion:
                        # 编程的单独拿出一种额外情况（敌人消失了，但是不在扩散模型中）
                        if i not in self.disappeared_enemy_diffusion_distortion:
                            self.disappeared_enemy_diffusion_distortion.append(i)
                        continue  # 没有接受概率的点表示模型失真了，将信息不对的敌人单独取出
                    pos_receive_list = list(pos_receive)
                    diffusion = copy.deepcopy(self.disappeared_enemy_diffusion[i]["diffusion"])
                    for pos0 in pos_transfer:
                        if self.disappeared_enemy_diffusion[i]["diffusion"][pos0] == 0:
                            continue  # 概率为0的分配不了概率
                        cur_pos_receive = []
                        self.disappeared_enemy_diffusion[i]["diffusion"][pos0] = 0  # 有视野的点概率清0
                        distance_list = [agent.map.get_distance(pos1, pos0) if diffusion[pos1] != 0 else 99 for pos1 in
                                         pos_receive_list]  # 当前转移概率的点与概率非零点的距离列表
                        for j in range(5):
                            b = distance_list.index(min(distance_list))  # 距离坐标中的最小值的索引
                            distance_list[b] = 99
                            cur_pos_receive.append(pos_receive_list[b])
                        for pos3 in cur_pos_receive:
                            self.disappeared_enemy_diffusion[i]["diffusion"][pos3] += 0.2 * diffusion[pos0]
                    # 测试概率是否为1
                    # c = 0
                    # for w in self.disappeared_enemy_diffusion[i]["diffusion"].keys():
                    #     c += self.disappeared_enemy_diffusion[i]["diffusion"][w]
                    # print(c)
                self.coord_flag = False
            self.get_enemy_coord(agent)
            self.step_time = agent.observation['time']['cur_step']

            agent.output_queue_lock.acquire()
            if agent.output_queue.full():
                agent.output_queue.get()
            agent.output_queue.put(self)
            # print("wocccccccc", self)
            agent.output_queue_lock.release()
            agent.run_flag = True

    def update_synchronous(self, agent):  # 同步更新态势函数
        if agent.observation['judge_info']:  # 确保有裁决信息
            for judge_message in agent.observation['judge_info']:  # 遍历裁决信息
                if judge_message["target_color"] == agent.color:
                    continue
                enemy_id = judge_message["target_obj_id"]
                if "damage" in judge_message.keys():  # 直瞄 间瞄 引导
                    if judge_message["damage"] > 0 and enemy_id in self.enemy.keys():
                        self.enemy[enemy_id]["cur_blood"] -= judge_message["damage"]
                    if judge_message["damage"] == 0 and enemy_id in self.enemy.keys():
                        if self.enemy[enemy_id]["sub_type"] == 2 and self.enemy[enemy_id]["keep"] == 1: # 步兵压制再次被压制的情况
                            self.enemy[enemy_id]["cur_blood"] -= 1  # 这样不准确
                    if self.enemy.get(enemy_id, None) is None:  # 字典没有enemy_id的时候，并且所有enemy_id对应的值都不是None
                        continue  # 同一时刻对敌方某个算子多次裁决，在血量小于等于0的时候的情况（不确定是否有其他情况报错）
                    elif self.enemy[enemy_id]["cur_blood"] <= 0:
                        if self.ufv_of_ifv.get(enemy_id):
                            # 战车死的时候清空对应无人战车
                            if self.enemy.get(self.ufv_of_ifv[enemy_id]):  #
                                # 同一时刻战车无人战车同时死亡了，删除无人战车后又删了次
                                del self.enemy[self.ufv_of_ifv[enemy_id]]
                        del self.enemy[enemy_id]
                if "final_damage" in judge_message.keys():  # 雷场
                    if judge_message["final_damage"] > 0 and enemy_id in self.enemy.keys():
                        self.enemy[enemy_id]["cur_blood"] -= judge_message["final_damage"]
                    if enemy_id not in self.enemy.keys():
                        continue
                    elif self.enemy[enemy_id]["cur_blood"] <= 0:
                        if self.ufv_of_ifv.get(enemy_id):
                            if self.enemy.get(self.ufv_of_ifv[enemy_id]):
                                # 战车死的时候清空对应无人战车
                                del self.enemy[self.ufv_of_ifv[enemy_id]]
                        del self.enemy[enemy_id]
        operators = agent.observation['operators'] + agent.observation["passengers"]
        self.id = [operator["obj_id"] for operator in operators if
                   operator["color"] == agent.color]  # 遍历所有的算子信息更新我方算子id
        # 更新self.enemy，self.enemy_coord，self.enemy_id，self.enemy_all_info属性
        for operator in agent.observation["operators"]:
            if operator["obj_id"] not in self.id:
                if operator["obj_id"] in self.enemy_id:
                    self.enemy[operator["obj_id"]]["last_step"] = agent.observation["time"]["cur_step"]
                    self.enemy[operator["obj_id"]]["keep"] = operator["keep"]
                    # 敌方解聚聚合后血量发生变化
                    if operator["blood"] != self.enemy[operator["obj_id"]]["cur_blood"]:
                        self.enemy[operator["obj_id"]]["cur_blood"] = operator["blood"]
                    # 知道敌方算子位置变化时更新
                    if operator["cur_hex"] != self.enemy[operator["obj_id"]]["coord"]:
                        self.enemy[operator["obj_id"]]["coord"] = operator["cur_hex"]
                else:  # 增加了解聚之后的添加，但是没有考虑解聚后的删除
                    self.enemy[operator["obj_id"]] = {
                        "obj_id": operator["obj_id"],
                        "color": operator["color"],
                        "sub_type": operator["sub_type"],
                        "keep": operator["keep"],
                        "last_step": agent.observation["time"]["cur_step"],
                        "coord": operator["cur_hex"],
                        "cur_blood": operator["blood"],
                    }
        # print(self.situation.enemy)
        operators_info = list(self.enemy.values())
        self.enemy_coord = [operator_info["coord"] for operator_info in operators_info]
        self.enemy_id = [operator_info["obj_id"] for operator_info in operators_info]
        # 记录敌人位置信息(要考虑敌方后面解聚出现的新id)
        see_enemy = {}
        for operator in agent.observation["operators"]:
            if operator['color'] != agent.color:  # 敌方的算子
                see_enemy[operator["obj_id"]] = operator['cur_hex']
                if operator["obj_id"] not in self.enemy_all_info.keys():  # 敌方解聚后看到的第一次添加
                    self.enemy_all_info[operator["obj_id"]] = {
                        "sub_type": operator["sub_type"],
                        "all_pos": [[agent.observation["time"]["cur_step"], operator["cur_hex"]]]
                    }
        # enemy_all_info_keys = list(self.situation.enemy_all_info.keys())
        # for i in enemy_all_info_keys:
        #     if i not in self.situation.enemy_id:
        #         del self.situation.enemy_all_info[i]
        for i in self.enemy_all_info.keys():
            # 确定某个敌人被消灭后，清空它的信息。如果之后用到将这部分信息存到另外一个属性中
            if self.enemy_all_info[i] is None:  # 被消灭后的算子不记录
                continue
            if i not in self.enemy_id:
                # del self.situation.enemy_all_info[i]  # error is dictionary changed size during iteration
                self.enemy_all_info[i] = None
                continue  # 2023.5.6添加
            if i in see_enemy.keys():
                pos0 = self.enemy_all_info[i]['all_pos'][-1][-1]
                if pos0 == see_enemy[i]:  # 看见的敌方算子坐标不变
                    continue
                else:  # 看见的敌方算子坐标变化了，记录看见坐标的第一个时间
                    new_pos_info = [agent.observation["time"]["cur_step"], see_enemy[i]]
                    self.enemy_all_info[i]["all_pos"].append(new_pos_info)
            else:
                pos0 = self.enemy_all_info[i]['all_pos'][-1][-1]
                if pos0 is None:  # 没有看见的敌人，之前也是看不见
                    continue
                else:  # 上一时刻可见，此刻不可见
                    new_pos_info = [agent.observation["time"]["cur_step"], None]
                    self.enemy_all_info[i]["all_pos"].append(new_pos_info)


    def get_enemy_coord(self, agent):  # 敌方解聚后是否也可以，区分红蓝方算子与可见敌方算子(遍历态势中的敌方算子也可以实现)
        enemy_diffusion_id = self.disappeared_enemy_diffusion.keys()  # 已经记录的丢失敌人的名单列表
        not_type = [3, 7, 11, 12]
        vehicle = [0, 1, 4, 9, 10, 13, 14, 15, 17, 18]
        infantry = [2, 16]
        aircraft0 = [6, 8]
        aircraft1 = [5]
        for i in self.enemy_all_info.keys():
            if self.enemy_all_info[i] is None:  # 被消灭后的算子不记录
                if i in enemy_diffusion_id:  # 被雷场或者炮兵间瞄消灭的不可视算子，清空其扩散模型
                    del self.disappeared_enemy_diffusion[i]
                continue  # 被消灭的算子不会出现扩散模型，（在被消灭的时候一定是可以看到的）
            if self.enemy_all_info[i]['sub_type'] in not_type:
                continue  # 敌方炮兵，巡飞弹，工事不参与未知敌人的未知预测
            end_info = self.enemy_all_info[i]['all_pos'][-1]
            end_info1 = self.enemy_all_info[i]['all_pos'][-2]
            if end_info[-1] is None and end_info[0] != 0:
                if i not in enemy_diffusion_id:  # 添加丢失的敌人
                    self.disappeared_enemy_diffusion[i] = {
                        "sub_type": self.enemy_all_info[i]["sub_type"],
                        "begin_time": end_info[0],
                        "diffusion": {end_info1[-1]: 1},
                        "radius": 0
                    }
                    # 初始状态敌人已经在最后一次观察到的格子的邻域
                    self.disappeared_enemy_diffusion[i]["radius"] += 1
                    disappeared_enemy_diffusion2(agent, end_info1[-1],
                                                 self.disappeared_enemy_diffusion[i]["diffusion"],
                                                 self.disappeared_enemy_diffusion[i]["radius"])
                else:
                    if self.disappeared_enemy_diffusion[i]["radius"] > 9:
                        continue  # 限制扩散模型的大小
                    time_difference = agent.observation["time"]["cur_step"] \
                                      - end_info[0] + 2  # 当前敌人消失的时间
                    if self.enemy_all_info[i]['sub_type'] in aircraft0:
                        if time_difference >= self.disappeared_enemy_diffusion[i]["radius"] * 4 :
                            # 更新一次扩散模型
                            self.disappeared_enemy_diffusion[i]["radius"] += 1
                            disappeared_enemy_diffusion2(agent, end_info1[-1],
                                                         self.disappeared_enemy_diffusion[i]["diffusion"],
                                                         self.disappeared_enemy_diffusion[i]["radius"])
                            # 此处根据我方视野对扩散模型进行修改
                            my_see_scope = copy.deepcopy(self.my_see_scope_all0[6])
                            diffusion_poss = set([pos for pos in
                                                  self.disappeared_enemy_diffusion[i]["diffusion"]
                                                  if self.disappeared_enemy_diffusion[i]["diffusion"][pos]
                                                  > 0])  # 概率修正只有概率大于0的参与
                            pos_transfer = my_see_scope.intersection(diffusion_poss)
                            pos_receive = diffusion_poss - pos_transfer
                            if not pos_receive or i in self.disappeared_enemy_diffusion_distortion:
                                # 编程的单独拿出一种额外情况（敌人消失了，但是不在扩散模型中）
                                if i not in self.disappeared_enemy_diffusion_distortion:
                                    self.disappeared_enemy_diffusion_distortion.append(i)
                                continue  # 没有接受概率的点表示模型失真了，将信息不对的敌人单独取出
                            pos_receive_list = list(pos_receive)
                            diffusion = copy.deepcopy(self.disappeared_enemy_diffusion[i]["diffusion"])
                            for pos0 in pos_transfer:
                                if self.disappeared_enemy_diffusion[i]["diffusion"][pos0] == 0:
                                    continue  # 概率为0的分配不了概率
                                cur_pos_receive = []
                                self.disappeared_enemy_diffusion[i]["diffusion"][pos0] = 0  # 有视野的点概率清0
                                distance_list = [agent.map.get_distance(pos1, pos0) if diffusion[pos1] != 0 else 99 for pos1 in
                                                 pos_receive_list]  # 当前转移概率的点与概率非零点的距离列表
                                for j in range(5):
                                    b = distance_list.index(min(distance_list))  # 距离坐标中的最小值的索引
                                    distance_list[b] = 99
                                    cur_pos_receive.append(pos_receive_list[b])
                                for pos3 in cur_pos_receive:
                                    self.disappeared_enemy_diffusion[i]["diffusion"][pos3] += 0.2*diffusion[pos0]
                    if self.enemy_all_info[i]['sub_type'] in aircraft1:
                        if time_difference >= self.disappeared_enemy_diffusion[i]["radius"] * 8 :
                            self.disappeared_enemy_diffusion[i]["radius"] += 1
                            disappeared_enemy_diffusion2(agent, end_info1[-1],
                                                         self.disappeared_enemy_diffusion[i]["diffusion"],
                                                         self.disappeared_enemy_diffusion[i]["radius"])
                            # 此处根据我方视野对扩散模型进行修改
                            my_see_scope = copy.deepcopy(self.my_see_scope_all0[5])
                            diffusion_poss = set([pos for pos in
                                                  self.disappeared_enemy_diffusion[i]["diffusion"]
                                                  if self.disappeared_enemy_diffusion[i]["diffusion"][pos]
                                                  > 0])  # 概率修正只有概率大于0的参与
                            pos_transfer = my_see_scope.intersection(diffusion_poss)
                            pos_receive = diffusion_poss - pos_transfer
                            if not pos_receive or i in self.disappeared_enemy_diffusion_distortion:
                                # 编程的单独拿出一种额外情况（敌人消失了，但是不在扩散模型中）
                                if i not in self.disappeared_enemy_diffusion_distortion:
                                    self.disappeared_enemy_diffusion_distortion.append(i)
                                continue  # 没有接受概率的点表示模型失真了，将信息不对的敌人单独取出
                            pos_receive_list = list(pos_receive)
                            diffusion = copy.deepcopy(self.disappeared_enemy_diffusion[i]["diffusion"])
                            for pos0 in pos_transfer:
                                if self.disappeared_enemy_diffusion[i]["diffusion"][pos0] == 0:
                                    continue  # 概率为0的分配不了概率
                                cur_pos_receive = []
                                self.disappeared_enemy_diffusion[i]["diffusion"][pos0] = 0  # 有视野的点概率清0
                                distance_list = [agent.map.get_distance(pos1, pos0) if diffusion[pos1] != 0 else 99 for pos1 in
                                                 pos_receive_list]  # 当前转移概率的点与概率非零点的距离列表
                                for j in range(5):
                                    b = distance_list.index(min(distance_list))  # 距离坐标中的最小值的索引
                                    distance_list[b] = 99
                                    cur_pos_receive.append(pos_receive_list[b])
                                for pos3 in cur_pos_receive:
                                    self.disappeared_enemy_diffusion[i]["diffusion"][pos3] += 0.2*diffusion[pos0]
                    if self.enemy_all_info[i]['sub_type'] in infantry:
                        if time_difference >= self.disappeared_enemy_diffusion[i]["radius"] * 144 :
                            self.disappeared_enemy_diffusion[i]["radius"] += 1
                            disappeared_enemy_diffusion2(agent, end_info1[-1],
                                                         self.disappeared_enemy_diffusion[i]["diffusion"],
                                                         self.disappeared_enemy_diffusion[i]["radius"])
                            # 此处根据我方视野对扩散模型进行修改
                            my_see_scope = copy.deepcopy(self.my_see_scope_all1[2])  # 掩蔽视野
                            my_see_scope1 = copy.deepcopy(self.my_see_scope_all0[2])
                            diffusion_poss = set([pos for pos in
                                                  self.disappeared_enemy_diffusion[i]["diffusion"]
                                                  if self.disappeared_enemy_diffusion[i]["diffusion"][pos]
                                                  > 0])  # 概率修正只有概率大于0的参与
                            pos_transfer = my_see_scope.intersection(diffusion_poss)
                            pos_transfer1 = my_see_scope1.intersection(diffusion_poss)
                            pos_receive1 = diffusion_poss - pos_transfer1
                            pos_transfer1 = pos_transfer1 - pos_transfer
                            pos_receive = diffusion_poss - pos_transfer
                            # 依据掩蔽地形修正
                            if not pos_receive or i in self.disappeared_enemy_diffusion_distortion:
                                # 编程的单独拿出一种额外情况（敌人消失了，但是不在扩散模型中）
                                if i not in self.disappeared_enemy_diffusion_distortion:
                                    self.disappeared_enemy_diffusion_distortion.append(i)
                                continue  # 没有接受概率的点表示模型失真了，将信息不对的敌人单独取出
                            pos_receive_list = list(pos_receive)
                            diffusion = copy.deepcopy(self.disappeared_enemy_diffusion[i]["diffusion"])
                            for pos0 in pos_transfer:
                                if self.disappeared_enemy_diffusion[i]["diffusion"][pos0] == 0:
                                    continue  # 概率为0的分配不了概率
                                cur_pos_receive = []
                                self.disappeared_enemy_diffusion[i]["diffusion"][pos0] = 0  # 有视野的点概率清0
                                distance_list = [agent.map.get_distance(pos1, pos0) if diffusion[pos1] != 0 else 99 for pos1 in
                                                 pos_receive_list]  # 当前转移概率的点与概率非零点的距离列表
                                for j in range(5):
                                    b = distance_list.index(min(distance_list))  # 距离坐标中的最小值的索引
                                    distance_list[b] = 99
                                    cur_pos_receive.append(pos_receive_list[b])
                                for pos3 in cur_pos_receive:
                                    self.disappeared_enemy_diffusion[i]["diffusion"][pos3] += 0.2*diffusion[pos0]
                            # 不依据掩蔽的修正一部分
                            if not pos_receive1 or i in self.disappeared_enemy_diffusion_distortion:
                                continue  # 敌人在扩散区域内掩蔽了，或者模型失真
                            pos_receive_list = list(pos_receive1)
                            diffusion = copy.deepcopy(self.disappeared_enemy_diffusion[i]["diffusion"])
                            for pos0 in pos_transfer1:
                                if self.disappeared_enemy_diffusion[i]["diffusion"][pos0] == 0:
                                    continue  # 概率为0的分配不了概率
                                cur_pos_receive = []
                                self.disappeared_enemy_diffusion[i]["diffusion"][pos0] = 0.5*diffusion[pos0]
                                # 有视野的点概率保留0.5倍
                                distance_list = [agent.map.get_distance(pos1, pos0) if diffusion[pos1] != 0 else 99 for pos1 in
                                                 pos_receive_list]  # 当前转移概率的点与概率非零点的距离列表
                                for j in range(5):
                                    b = distance_list.index(min(distance_list))  # 距离坐标中的最小值的索引
                                    distance_list[b] = 99
                                    cur_pos_receive.append(pos_receive_list[b])
                                for pos3 in cur_pos_receive:
                                    self.disappeared_enemy_diffusion[i]["diffusion"][pos3] += 0.1*diffusion[pos0]
                    else:
                        if time_difference >= self.disappeared_enemy_diffusion[i]["radius"] * 20 :
                            self.disappeared_enemy_diffusion[i]["radius"] += 1
                            disappeared_enemy_diffusion2(agent, end_info1[-1],
                                                         self.disappeared_enemy_diffusion[i]["diffusion"],
                                                         self.disappeared_enemy_diffusion[i]["radius"])
                            # 此处根据我方视野对扩散模型进行修改
                            my_see_scope = copy.deepcopy(self.my_see_scope_all1[0])
                            my_see_scope1 = copy.deepcopy(self.my_see_scope_all0[0])
                            # my_see_scope1 = set()
                            # for operator in self.observation["operators"]:
                            #     if operator["color"] != self.color:
                            #         continue  # 只有我方算子提供视野
                            #     single_see_scope = self.get_see_scope(operator, 0)
                            #     my_see_scope1 = my_see_scope1.union(single_see_scope)
                            diffusion_poss = set([pos for pos in
                                                  self.disappeared_enemy_diffusion[i]["diffusion"]
                                                  if self.disappeared_enemy_diffusion[i]["diffusion"][pos]
                                                  > 0])  # 概率修正只有概率大于0的参与
                            pos_transfer = my_see_scope.intersection(diffusion_poss)
                            pos_transfer1 = my_see_scope1.intersection(diffusion_poss)
                            pos_receive1 = diffusion_poss - pos_transfer1
                            pos_transfer1 = pos_transfer1 - pos_transfer
                            pos_receive = diffusion_poss - pos_transfer
                            # 依据掩蔽地形修正
                            if not pos_receive or i in self.disappeared_enemy_diffusion_distortion:
                                # 编程的单独拿出一种额外情况（敌人消失了，但是不在扩散模型中）
                                if i not in self.disappeared_enemy_diffusion_distortion:
                                    self.disappeared_enemy_diffusion_distortion.append(i)
                                continue  # 没有接受概率的点表示模型失真了，将信息不对的敌人单独取出
                            pos_receive_list = list(pos_receive)
                            diffusion = copy.deepcopy(self.disappeared_enemy_diffusion[i]["diffusion"])
                            for pos0 in pos_transfer:
                                if self.disappeared_enemy_diffusion[i]["diffusion"][pos0] == 0:
                                    continue  # 概率为0的分配不了概率
                                cur_pos_receive = []
                                self.disappeared_enemy_diffusion[i]["diffusion"][pos0] = 0  # 有视野的点概率清0
                                distance_list = [agent.map.get_distance(pos1, pos0) if diffusion[pos1] != 0 else 99 for pos1 in
                                                 pos_receive_list]  # 当前转移概率的点与概率非零点的距离列表
                                for j in range(5):
                                    b = distance_list.index(min(distance_list))  # 距离坐标中的最小值的索引
                                    distance_list[b] = 99
                                    cur_pos_receive.append(pos_receive_list[b])
                                for pos3 in cur_pos_receive:
                                    self.disappeared_enemy_diffusion[i]["diffusion"][pos3] += 0.2*diffusion[pos0]
                            # 不依据掩蔽的修正一部分
                            if not pos_receive1 or i in self.disappeared_enemy_diffusion_distortion:
                                continue  # 敌人在扩散区域内掩蔽了，或者模型失真
                            pos_receive_list = list(pos_receive1)
                            diffusion = copy.deepcopy(self.disappeared_enemy_diffusion[i]["diffusion"])
                            for pos0 in pos_transfer1:
                                if self.disappeared_enemy_diffusion[i]["diffusion"][pos0] == 0:
                                    continue  # 概率为0的分配不了概率
                                cur_pos_receive = []
                                self.disappeared_enemy_diffusion[i]["diffusion"][pos0] = 0.5*diffusion[pos0]
                                # 有视野的点概率保留0.5倍
                                distance_list = [agent.map.get_distance(pos1, pos0) if diffusion[pos1] != 0 else 99 for pos1 in
                                                 pos_receive_list]  # 当前转移概率的点与概率非零点的距离列表
                                for j in range(5):
                                    b = distance_list.index(min(distance_list))  # 距离坐标中的最小值的索引
                                    distance_list[b] = 99
                                    cur_pos_receive.append(pos_receive_list[b])
                                for pos3 in cur_pos_receive:
                                    self.disappeared_enemy_diffusion[i]["diffusion"][pos3] += 0.1*diffusion[pos0]
                            # 测试概率是否为1
                            # c = 0
                            # for w in self.disappeared_enemy_diffusion[i]["diffusion"].keys():
                            #     c += self.disappeared_enemy_diffusion[i]["diffusion"][w]
                            # print(c)
            else:
                if i in enemy_diffusion_id:  # 看到消失的敌人
                    del self.disappeared_enemy_diffusion[i]
                if i in self.disappeared_enemy_diffusion_distortion:  # 看到扩散模型失真失真的敌人
                    self.disappeared_enemy_diffusion_distortion.remove(i)